home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Visual Basic Source Code
/
Visual Basic Source Code.iso
/
vbsource
/
metkit
/
catalog.cpp
< prev
next >
Wrap
C/C++ Source or Header
|
1997-06-07
|
8KB
|
224 lines
// Copyright (C) 1996, 1997 Meta Four Software. All rights reserved.
//
// Recursive directory scanner sample code
//
//! rev="$Id: catalog.cpp,v 1.3 1997/05/27 00:06:33 jcw Rel $"
/////////////////////////////////////////////////////////////////////////////
//
// The following two globally accesible routines are defined below:
//
// c4_View fScanDirectories(const char* path_);
// c4_String fFullPath(c4_View& dirs_, int dirNum_);
//
// The fScanDirectories routine does all the work, and completely hides all
// Windows 16/32 specifics by returning a generalized catalog tree object.
// In contrast with normal C++ conventions, nearly all MetaKit objects are
// reference counted. This takes care of fully automatic cleanup after use.
//
// The structure of the object returned by fScanDirectories is as follows:
//
// Property Type Description
// ======== ==== ===========
//
// dirs nested Contains 1 record per directory
// parent integer Index of parent entry
// name string Name of this directory
// files nested Contains 1 record per file entry
// name string Name of this file
// size string File size
// date integer Modification date (DOS format 7+4+5 bits)
//
// The first directory entry (entry 0) is special: the parent is set to zero
// (points to itself), and the name is the base path name (see path_ arg).
//
// In C++ notation, a declaration for this object would be something like:
//
// struct
// {
// int parent;
// char* name;
//
// struct
// {
// char* name;
// long size;
// int date;
//
// } files []; // variable size, not allowed in C++
//
// } dirs [];
//
/////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "catalog.h"
// forward declaration
static void ScanSubDir(c4_View&, int, const c4_String&);
/////////////////////////////////////////////////////////////////////////////
// Property definitions
c4_ViewProp pFiles ("files");
c4_IntProp pParent ("parent"),
pSize ("size"),
pDate ("date");
c4_StringProp pName ("name");
/////////////////////////////////////////////////////////////////////////////
// Scan a directory tree and return a corresponding structure for it
c4_View fScanDirectories(const char* path_)
{
// Start with a view containing the root directory entry
c4_View dirs;
dirs.Add(pName [path_]);
// This loop "automagically" handles the recursive traversal of all
// subdirectories. The trick is that each scan may add new entries
// at the end, causing this loop to continue (GetSize() changes!).
for (int i = 0; i < dirs.GetSize(); ++i)
{
c4_String path = fFullPath(dirs, i);
TRACE("Scanning '%s' ...\n", (const char*) path);
ScanSubDir(dirs, i, path);
}
// The returned object contains the entire directory tree.
// Everything is automatically destroyed when no longer referenced.
return dirs;
}
/////////////////////////////////////////////////////////////////////////////
// Reconstruct the full path name from a subdirectory index in the tree
c4_String fFullPath(c4_View& dirs_, int dirNum_)
{
// Prefix all parent dir names until the root level is reached
c4_String path;
for (;;)
{
path = pName (dirs_[dirNum_]) + "\\" + path;
if (dirNum_ == 0)
return path; // this result always has a trailing backslash
dirNum_ = (int) pParent (dirs_[dirNum_]);
}
}
/////////////////////////////////////////////////////////////////////////////
// There are two versions of ScanSubDir, one for Win32 and one for Win16
#ifdef _WIN32
// Convert a Win32 filedate back to the good old DOS format
static WORD DosDate(FILETIME& ft)
{
SYSTEMTIME st;
if (!FileTimeToSystemTime(&ft, &st))
return 0;
return (WORD) (((st.wYear-1980) << 9) | (st.wMonth << 5) | st.wDay);
}
// Scan subdirectory and update the directory structure
static void ScanSubDir(c4_View& dirs_, int dirNum_, const c4_String& path_)
{
WIN32_FIND_DATA fd;
HANDLE h = FindFirstFile(path_ + "*", &fd);
if (h)
{
// Some notes on efficiency:
//
// 1) It is probably faster to fill a view with data, and
// then store it in a persistent field, than to modify
// persistent structures in place. In this example, this
// is needed anyway, since we also sort all filenames.
//
// 2) If possible, avoid constructing rows inside a loop.
// For that reason, both 'prop [const]' and 'row + row'
// are relatively inefficient.
// c4_View files = pFiles (dirs_[dirNum_]);
c4_View files;
c4_Row dir, file;
do
{
if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
if (fd.cFileName[0] == '.')
continue;
// dirs_.Add(pParent [dirNum_] + pName [fd.cFileName]);
pParent (dir) = dirNum_;
pName (dir) = fd.cFileName;
dirs_.Add(dir);
}
else
{
// files.Add(pName [fd.cFileName] + pSize [fd.nFileSizeLow]
// + pDate [DosDate(fd.ftLastWriteTime)]);
pName (file) = fd.cFileName;
pSize (file) = fd.nFileSizeLow;
pDate (file) = DosDate(fd.ftLastWriteTime);
files.Add(file);
}
} while (FindNextFile(h, &fd));
pFiles (dirs_[dirNum_]) = files.SortOn(pName);
FindClose(h);
}
}
#else
#include <dos.h>
// Scan subdirectory and update the directory structure
static void ScanSubDir(c4_View& dirs_, int dirNum_, const c4_String& path_)
{
_find_t fd;
if (_dos_findfirst(path_ + "*.*", _A_SUBDIR, &fd) == 0)
{
c4_View files;
c4_Row dir, file;
do
{
if (fd.attrib & _A_SUBDIR)
{
if (fd.name[0] == '.')
continue;
pParent (dir) = dirNum_;
pName (dir) = fd.name;
dirs_.Add(dir);
}
else
{
pName (file) = fd.name;
pSize (file) = fd.size;
pDate (file) = fd.wr_date;
files.Add(file);
}
} while (_dos_findnext(&fd) == 0);
pFiles (dirs_[dirNum_]) = files.SortOn(pName);
}
}
#endif
/////////////////////////////////////////////////////////////////////////////